package com.vertx.web.verticle;

import com.vertx.core.context.AbstractApplicationContext;
import com.vertx.core.context.AnnotationApplicationContext;
import com.vertx.data.utils.DbUtils;
import com.vertx.web.bean.VertxBeanFactory;
import io.vertx.core.Context;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpMethod;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.*;
import io.vertx.ext.web.sstore.LocalSessionStore;
import io.vertx.serviceproxy.ServiceException;
import io.vertx.serviceproxy.ServiceExceptionMessageCodec;
import org.apache.log4j.Logger;
import java.util.HashSet;
import java.util.Set;

import static com.sun.deploy.net.HttpRequest.CONTENT_TYPE;

/****
 * 实现abstractVerticle核心类
 */
public abstract class AbstractImplVerticle extends BaseServiceVerticle {

    private Logger logger = Logger.getLogger(AbstractImplVerticle.class);

    private static final String APPLICATION_JSON = "application/json";

    protected static AbstractApplicationContext applicationContext;

    protected Router router;


    @Override
    public void init(Vertx vertx, Context context) {
        super.init(vertx, context);
        setRouter(vertx);
        if (null==applicationContext) {
            try {
                String[] scanPackage=new String[]{config().getString("scanPackage")};
                applicationContext = new AnnotationApplicationContext(scanPackage,new VertxBeanFactory(router,vertx,scanPackage));
                applicationContext.refresh(vertx);
                //获取一个默认的配置
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //初始化jdbc
        new DbUtils().initJdbcAsync(vertx,config(),res->{
            if(res.failed()){
                logger.error("jdbc init is error"+res.cause());
            }else{
                logger.info("jdbc init succeed");
            }
        });
        vertx.eventBus().registerDefaultCodec(ServiceException.class,new ServiceExceptionMessageCodec());//设置EventBus通信编码

    }


    private void setRouter(Vertx vertx) {
        router = Router.router(vertx);
        enableLocalSession(router);
        enableCorsSupport(router);
        router.route().consumes(APPLICATION_JSON);
        router.route().produces(APPLICATION_JSON);
        router.route().handler(BodyHandler.create());
        router.route().handler(routingContext -> {
            routingContext.response().headers().add(CONTENT_TYPE, APPLICATION_JSON);
            routingContext.next();
        });

    }

    @Override
    public void start(Future<Void> startFuture) throws Exception {
       vertx.createHttpServer().requestHandler(router::accept).listen(this.config().getInteger("http.port", 8080),
                res -> {
                    if (res.succeeded()) {
                        startFuture.succeeded();
                        logger.info(" >> start rest service  on port " + this.config().getInteger("http.port", 8080));
                    } else {
                        startFuture.fail(res.cause());
                        logger.error(">> start rest service failed !");
                    }
        });
    }

    /***
     * 开启session ,cookie支持
     * @param router
     */
    protected void enableLocalSession(Router router) {
        router.route().handler(CookieHandler.create());
        LocalSessionStore localSessionStore=LocalSessionStore.create(vertx);
        SessionHandler sessionHandler=SessionHandler.create(localSessionStore);
        router.route().handler(sessionHandler);
    }

    /***
     * 设置跨域
     * @param router
     */
    protected void enableCorsSupport(Router router) {
        Set<String> allowHeaders = new HashSet<>();
        allowHeaders.add("x-requested-with");
        allowHeaders.add("Access-Control-Allow-Origin");
        allowHeaders.add("origin");
        allowHeaders.add("Content-Type");
        allowHeaders.add("accept");
        router.route().handler(CorsHandler.create("*")
                .allowedHeaders(allowHeaders)
                .allowedMethod(HttpMethod.GET)
                .allowedMethod(HttpMethod.POST)
                .allowedMethod(HttpMethod.PUT)
                .allowedMethod(HttpMethod.DELETE)
                .allowedMethod(HttpMethod.PATCH)
                .allowedMethod(HttpMethod.OPTIONS)
        );
    }


}
